package com.homelock.thread;

import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.fastjson.JSONObject;
import com.homelock.constants.LockCmdEnum;
import com.homelock.processor.BaseMsgProcessor;
import com.homelock.processor.CmdMeta;
import com.pi.base.enumerate.redis.RedisCacheEnum;
import com.pi.base.util.cache.RedisUtil;
import com.pi.base.util.lang.ByteUtil;
import com.pi.smart.client.ins.comm.domain.BaseWifiCmd;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;

/**
 * 消息监听接口
 */
@Component
public class ZxLockCmdTask implements ApplicationRunner {
    private static final Logger logger = LoggerFactory.getLogger(ZxLockCmdTask.class);

    private static volatile boolean isRuning = true;
    private static Map<String,BaseMsgProcessor> processorMap = null;
    static final int CMD_DEV = 0xC1;

    @Value("${task.zx.listen.enable}")
    private boolean listenEnable;

    @Autowired
    List<BaseMsgProcessor> baseMsgProcessors;
    @Autowired
    Executor asyncTaskExecute;

    @Override
    public void run(ApplicationArguments args) {
        if(!listenEnable){
            logger.info("振兴锁监听线程状态为关闭");
            return;
        }
        asyncTaskExecute.execute(()->{
            logger.info("[振兴锁监听数据]线程启动");
            if(null == processorMap){
                logger.error("[振兴锁监听数据]没有可解析数据的handle,线程结束");
                return;
            }

            // 测试使用的key,防止读取正式的数据造成数据丢失
         //   String key = "SMART_DEVICELOCK_WIFI_TEST";

            while (isRuning){
                BaseWifiCmd zxMsgCmd = null;
                try {
                    zxMsgCmd = RedisUtil.blpop(RedisCacheEnum.SMART_DEVICELOCK_WIFI);
                 //   zxMsgCmd = RedisUtil.blpop(key);

                } catch (ClassNotFoundException e) {
                    logger.error("[振兴锁监听数据]类型转换异常："+e.getMessage());
                    continue;
                } catch (IOException e) {
                    logger.error("[振兴锁监听数据]redis读取异常："+e.getMessage());
                    continue;
                    // io异常 需要转换到本地内存队列，同时发送监控信息给管理员
                }
                if(null == zxMsgCmd){
                    // redis brpop 超时拿到null;
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        logger.error("振兴锁监听线程sleep被中断");
                        shutdown();
                    }
                    continue;

                }
                // 数据解析异常或者blpop超时,重新去读
               int cmdLen =  Optional.ofNullable(zxMsgCmd.getCmd())
                        .map(bytes -> bytes.length).orElse(0);
                if(cmdLen < 6){
                     logger.info("[振兴锁监听数据]指令长度异常- {}", cmdLen);
                    Optional.ofNullable(zxMsgCmd).ifPresent( d ->logger.error("[振兴锁监听数据]指令数据- {}", JSONUtils.toJSONString(d)));
                    continue;
                }
                logger.info("[振兴锁监听数据]指令数据- {}", ByteUtil.byteToHex(zxMsgCmd.getCmd()));
                int cmd = zxMsgCmd.getCmd()[0]&0xFF;
                logger.info("cmd:{}",ByteUtil.byteToHex(new byte[]{zxMsgCmd.getCmd()[0]}));
                if(cmd < 0 || (cmd & 0xFF) != CMD_DEV){
                    return;
                }
                int optCode = zxMsgCmd.getCmd()[1] & 0xFF;
                int typeCode = zxMsgCmd.getCmd()[2] & 0xFF;
                LockCmdEnum currentEnum = LockCmdEnum.optCodeOf((byte)optCode);
                String mapKey;
                if(currentEnum.getCode() >= 0){ // <0 只判断一位 后面的第二位不作为这边的消息分类处理
                     mapKey = getKey(optCode,typeCode);
                }else {
                    mapKey = String.valueOf(optCode);
                }
                logger.info("optCode:{},typeCode:{}",optCode,typeCode);
                logger.info("mapKey:{}",mapKey);;
                if(processorMap.containsKey(mapKey)){
                    processorMap.get(mapKey).handle(zxMsgCmd);
                }else{
                    logger.info("[振兴锁监听数据]当前未定义指令- {}", mapKey);
                }
            }
        });
    }


    private  String getKey(int mapKey1,int mapKey2){
        return  new StringBuilder().append(mapKey1).append("_").append(mapKey2).toString();
    }


    @PostConstruct
    public void init(){
        if(CollectionUtils.isEmpty(baseMsgProcessors)){
            processorMap = null;
        }
        processorMap = new ConcurrentHashMap<String,BaseMsgProcessor>(baseMsgProcessors.size()*4/3+1);
        for(BaseMsgProcessor item:baseMsgProcessors){
            CmdMeta cmdItem = item.getClass().getAnnotation(CmdMeta.class);
            if(null != cmdItem || (LockCmdEnum.EMPTY == cmdItem.value() && cmdItem.values() == null)){
                if(LockCmdEnum.EMPTY != cmdItem.value()) {
                    processorMap.putIfAbsent(cmdItem.value().getValue(), item);
                }else{
                    for(LockCmdEnum value:cmdItem.values()){
                        processorMap.putIfAbsent(value.getValue(),item);
                    }
                }
            }
        }
    }

    @PreDestroy
    public void shutdown(){
        this.isRuning = false;
    }
}
